package com.aote.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.aote.component.format.FormatFactory;
import com.aote.model.table.tdprocessor.TdProcessor;
import com.aote.util.ComponentHelper;
import com.aote.util.ExpressionHelper;
import com.aote.util.StringHelper;
import com.aote.util.ThreadLocals;
import com.browsesoft.Entity;
import com.browsesoft.ExtendElement;
import com.browsesoft.baseadapter.AddupModel;
import com.browsesoft.baseadapter.SumModel;
import com.browsesoft.htmlcomponent.HTMLBasicComponent;
import com.browsesoft.htmlcomponent.HTMLLazyTable;
import com.browsesoft.htmlcomponent.HTMLTableComponent;
import com.browsesoft.htmlcomponent.HTMLTableModel;
import com.browsesoft.htmlcomponent.SpecialCellsModel;
import com.browsesoft.tools.XMLTool;
import com.browsesoft.user.User;

/**
 * 显示数据的表格模型。数据获得由子类完成。数据必须存放在map组成的列表中。map中的key为数据名称，value为数据值。
 * 每列显示的数据名称在模板上配置，配置在表头单元格里。配置格式为：
 * ，在表头单元格的span的field属性里指明。
 */
public abstract class DataShowTableModel implements HTMLTableModel, AddupModel,
		SumModel, HTMLLazyTable, SpecialCellsModel {
	/**
	 * 组件
	 */
	protected HTMLBasicComponent component = null;

	/**
	 * 列说明列表
	 */
	protected List columns = new ArrayList();

	/**
	 * 数据，链表中的每一项是一个hashtable,hashtable中存放的是 字段名，值
	 */
	protected List datas = new LinkedList();

	/**
	 * 本页开始及结束行
	 */
	public int start;

	public int end;

	// 小计值
	private Map addups = new HashMap();

	/**
	 * 要重复替换参数的属性
	 */
	private Map subParams = new HashMap();

	// 被选中的行号
	private List selected = new LinkedList();

	// 默认全选或都不选
	private String allOrNull = new String();

	public void init(HttpServletRequest request) throws Exception {
		// 得到表头定义列名称
		this.columns = getColumns();
		this.allOrNull = this.component.getElement().getAttribute("allornull");
	}

	public void modifyCellValue(Element td, Document doc, int row, int col) {
		Hashtable data = (Hashtable) this.datas.get(row);
		// 得到td中得字段名称
		Column column = (Column) this.columns.get(col);
		String field = column.field;
		if (field != null) {
			Element elem = column.element;
			String value = getValue(data, elem, field);
			ExtendElement.replaceElementContext(td, value);
		} else {
			ExtendElement.replaceElementContext(td, "");
			LinkedList list = ExtendElement.findElements(td, "type", "link");
			Element ele = (Element) list.iterator().next();
			String onclick = ele.getAttribute("onclick");
			if (onclick != null) {
				onclick = StringHelper.replaceStr(data, onclick);
				ele.setAttribute("onclick", onclick);
			}
			System.out.println(onclick);
			// StringHelper.r
		}
	}

	/**
	 * 得到单项值
	 */
	public String getValue(Hashtable data, Element element, String field) {
		throw new UnsupportedOperationException();
	}

	public void service(HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		this.setDatas(request);
		this.completeDatas();
		this.disposeAddup();
		// 得到选择结果
		setSelected(request);
	}

	private void setSelected(HttpServletRequest request) {
		// action=search，说明是带值操作，不依据result结果处理，依据初始值处理，action为空
		// 第一次进入，也不依据result处理
		String action = request.getParameter("action");
		if (action == null || action.equals("search")
				|| action.equals("refresh")) {
			if (this.selected != null && !this.selected.isEmpty()) {
				this.selected.clear();
			}
			if (this.allOrNull == null) {
				return;
			}
			if (this.allOrNull.equals("all") && this.datas != null) {
				for (int i = 0; i < this.datas.size(); i++) {
					this.selected.add(Integer.toString(i));
				}
				return;
			}
			if (this.allOrNull.equals("null")) {
				this.selected = null;
				return;
			}
		}
		// 依据选择结果处理
		String select = request.getParameter("result");
		if (select != null) {
			// 如果要进行批量选择处理
			if (this.component.getElement().hasAttribute("batchselect")) {
				this.batchSelect(select);
				return;
			}
			this.selected = StringHelper.getStrings(select, ",");
			return;
		}
	}

	/**
	 * 执行批量数据处理，如果新增了一项，补全原来最后一项与新增项的数据，如果删除一项， 删除该项后面的数据
	 */
	private void batchSelect(String select) {
		if (this.selected == null || select == null || select.equals("")) {
			return;
		}
		List nSelect = StringHelper.getStrings(select, ",");
		// 如果没有动，不处理
		if (nSelect.size() == this.selected.size()) {
			return;
		}
		// 如果新增
		else if (nSelect.size() > this.selected.size()) {
			// 补全新增与原来数据最后一项差距
			int oLast = -1;
			try {
				oLast = Integer.parseInt((String) this.selected
						.get(this.selected.size() - 1));
			} catch (Exception e) {
				// 忽略原来没有数据异常
			}
			int nLast = Integer.parseInt((String) nSelect
					.get(nSelect.size() - 1));
			for (int i = oLast + 1; i <= nLast; i++) {
				this.selected.add(i + "");
			}
		}
		// 如果删除
		else {
			// 删除后面的数据
			for (int i = 0; i < nSelect.size(); i++) {
				String value = (String) nSelect.get(i);
				// 如果值与位置不符，删除
				if (!value.equals(i + "")) {
					this.selected.remove(value);
				}
			}
			// 删除缺少的数据
			this.selected.remove(this.selected.size() - 1);
		}
	}

	/**
	 * 设置数据
	 */
	protected void setDatas(HttpServletRequest request) throws Exception {
	}

	/**
	 * 补全datas
	 */
	private void completeDatas() {
		Element head = ((HTMLTableComponent) this.component).getHeadElement();
		Element template = (Element) head.getElementsByTagName("template")
				.item(0);
		NodeList nodes = template.getElementsByTagName("td");
		for (int i = 0; i < nodes.getLength(); i++) {
			Element td = (Element) nodes.item(i);
			Element span = (Element) td.getElementsByTagName("span").item(0);
			if (span == null || !span.hasAttribute("expression")) {
				continue;
			}
			for (int j = 0; j < this.getRowCount(); j++) {
				this.getValue((Hashtable) this.datas.get(j), span, null);
			}
		}
	}

	/**
	 * 得到所有列的类型描述
	 * 
	 * @return
	 */
	private List getColumns() {
		List result = new ArrayList();
		// 得到所有表头列元素，得到列元素的文体节点值及类型
		Element trHeadElem = (Element) ExtendElement.findElements(
				this.component.getElement(), "type", "head").get(0);
		Element template = (Element) trHeadElem
				.getElementsByTagName("template").item(0);
		NodeList list = template.getElementsByTagName("td");
		for (int i = 0; i < list.getLength(); i++) {
			Element tdElem = (Element) list.item(i);
			Column column = new Column();
			result.add(column);
			try {
				String cname = ExtendElement.getTextContent(tdElem);
				column.name = cname;
			} catch (RuntimeException e) {
				column.name = "　";
			}
			String colType = tdElem.getAttribute("type");
			column.type = colType;
			// 有span元素，从span中得到相关描述
			Element span = this.getSpan(tdElem);
			if (span != null) {
				String field = span.getAttribute("field");
				column.field = field;
				String addup = span.getAttribute("addup");
				column.addup = addup;
				column.element = span;
			}
		}
		return result;
	}

	/**
	 * 得到span元素
	 */
	private Element getSpan(Element td) {
		NodeList list = td.getElementsByTagName("span");
		if (list == null || list.getLength() == 0) {
			return null;
		}
		Element span = (Element) list.item(0);
		return span;
	}

	public int getColumnCount() {
		return this.columns.size();
	}

	public String getType(int col) {
		Column column = (Column) this.columns.get(col);
		return column.type;
	}

	public int getRowCount() {
		if (this.datas == null || this.datas.isEmpty()) {
			return 0;
		}
		return this.datas.size();
	}

	public void setComponent(HTMLBasicComponent component) {
		this.component = component;
	}

	public void setCondition(String condition) {
	}

	public void updatePageElement(HTMLBasicComponent c) throws Exception {
		Element element = this.component.getPage().getElement();
		List list = ExtendElement.findElements(element, "name", "result");
		if (list != null && !list.isEmpty()) {
			Element result = (Element) list.get(0);
			String string = this.getString(this.selected);
			result.setAttribute("value", string);
		}
	}

	private String getString(List list) {
		String result = new String();
		if (list == null || list.isEmpty()) {
			return null;
		}
		Iterator iter = list.iterator();
		while (iter.hasNext()) {
			String string = (String) iter.next();
			if (StringHelper.isNull(result)) {
				result = string;
			} else {
				result = result + "," + string;
			}
		}
		return result;
	}

	public String getColumnName(int index) {
		Column column = (Column) this.columns.get(index);
		return column.name;
	}

	public void modifyAddupCell(Document doc, Element td, int col)
			throws Exception {
		Column column = (Column) this.columns.get(col);
		String str = " ";
		// 有小计标识,得到小计值
		String addup = column.addup;
		String field = column.field;
		if (addup != null && addup.equals("addup")) {
			str = (String) this.addups.get(field);
		}
		Node node = XMLTool.createTextNode(doc, str);
		// 替换单元格
		ExtendElement.replaceElementContext(td, node);
	}

	/**
	 * 计算小计值
	 */
	private void disposeAddup() {
		Iterator iter = this.columns.iterator();
		while (iter.hasNext()) {
			Column column = (Column) iter.next();
			String addup = column.addup;
			String field = column.field;
			if (addup != null && addup.equals("addup")) {
				String str = getSum(column, null, this.start, this.end);
				this.addups.put(field, str);
			} else if (addup != null) {
				this.addups.put(field, addup);
			}
		}
	}

	public void modifySumCell(Document doc, Element td, int col)
			throws Exception {
		Column column = (Column) this.columns.get(col);
		String str = " ";
		// 有小计标识,得到小计值
		String addup = column.addup;
		if (addup != null && addup.equals("addup")) {
			str = getSum(column, td, 0, Integer.MAX_VALUE);
			str = FormatFactory.getInstance().format(str, td);
		}else if(addup!=null){
			str = addup;
		}
		Node node = XMLTool.createTextNode(doc, str);
		// 替换单元格
		ExtendElement.replaceElementContext(td, node);
	}

	/**
	 * 得到某列小计值,从start到end项,如果到最后一项,可以让end=Integer.MAX_VALUE
	 */
	private String getSum(Column column, Element td, int start, int end) {
		String name = column.field;
		// 取得实体
		Iterator iter = this.datas.iterator();
		double sum = 0;
		// 对于每一个
		for (int i = 0; i < end && iter.hasNext(); i++) {
			Hashtable data = (Hashtable) iter.next();
			// 开始行前面的,不计算
			if (i < start) {
				continue;
			}
			try {
				// 将该列的值累加
				sum += Double.parseDouble((String) data.get(name));
			} catch (Exception e) {
			}
		}
		Element span = column.element;
		String str = FormatFactory.getInstance().format(sum + "", span);
		return str;
	}

	/**
	 * 仅用做页面小计时,判断页面开始及结束行
	 */
	public void loadData(int start, int end) {
		this.start = start;
		this.end = end;
	}

	/**
	 * 处理特殊单元格
	 */
	public void disposeSpecialTd(Element td, int row, String type) {
		try {
			Element element = null;
			if (type.equals("radiobox") || type.equals("checkbox")) {
				element = (Element) td.getElementsByTagName("input").item(0);
				this.disposeCheckBox(element, row, type);
			} else if (type.equals("link")) {
				element = (Element) td.getElementsByTagName("a").item(0);
				this.disposeLinkElement(element, row);
			} else if (type.equals("special")) {
				// 特殊单元格处理接口处理
				String className = td.getAttribute("classname");
				TdProcessor processor = (TdProcessor) Class.forName(className)
						.newInstance();
				processor
						.process(td, (Map) this.datas.get(row), this.component);
				// 根据form组件的实体中的选中信息，设置状态
				Entity entity = ComponentHelper.getFormEntity(this.component);
				String attri = (String) entity.getAttributes().get("checked");
				NodeList nodes = td.getElementsByTagName("input");
				for (int i = 0; i < nodes.getLength(); i++) {
					Element box = (Element) nodes.item(i);
					String value = box.getAttribute("value");
					if (attri != null && attri.equals(value)) {
						box.setAttribute("checked", "checked");
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	protected void disposeCheckBox(Element element, int row, String type) {
		String name = Integer.toString(row);
		if (element.hasAttribute("field")) {
			String field = element.getAttribute("field");
			Hashtable data = (Hashtable) this.datas.get(row);
			String value = (String) data.get(field);
			element.setAttribute("value", value);
		}
		if (type.equals("checkbox")) {
			element.setAttribute("name", name);
		}
		// 设置选中状态
		if (this.selected != null && !this.selected.isEmpty()
				&& this.selected.contains(name)) {
			element.setAttribute("checked", "checked");
		} else {
			element.removeAttribute("checked");
		}
	}

	/**
	 * 处理连接
	 */
	protected void disposeLinkElement(Element element, int row) {
		Hashtable data = (Hashtable) this.datas.get(row);
		String field = element.getAttribute("field");
		// 要替换的参数，可以是";"隔开的多个
		String string = element.getAttribute("subcontent");
		List subContents = StringHelper.getStrings(string, ";");
		// 参数的值，如果是多参数，值必须是表达式，且每个表达式按顺序用";"隔开
		String str = (String) this.getValue(data, element, field);
		List values = StringHelper.getStrings(str, ";");
		String onclick = new String();
		// 得到onclick属性
		if (this.subParams.isEmpty() || !this.subParams.containsKey(element)) {
			onclick = element.getAttribute("onclick");
			this.subParams.put(element, onclick);
		} else {
			onclick = (String) this.subParams.get(element);
		}
		// 替换参数
		if (subContents != null || !subContents.isEmpty()) {
			for (int i = 0; i < subContents.size(); i++) {
				onclick = onclick.replaceAll((String) subContents.get(i),
						(String) subContents.get(i) + (String) values.get(i));
			}
		} else {
			onclick = onclick.replaceAll("activityID=", "activityID="
					+ (String) values.get(0));
		}
		element.setAttribute("onclick", onclick);
	}

	/**
	 * 清除数据
	 */
	public void clearDatas() {
		this.datas.clear();
	}

	/**
	 * 根据列名得数据
	 */
	public String getDataByColumnName(String name) {
		Column col = getColumByName(name);
		String summer = this.getSum(col, null, 0, this.datas.size());
		if (Double.parseDouble(summer) == 0) {
			if (this.addups.containsKey(name)) {
				return (String) this.addups.get(name);
			} else {
				return summer;
			}
		} else {
			this.addups.put(name, summer);
			return summer;
		}
	}

	/**
	 * 被选择行的某列求和
	 */
	public String getSumOfSelected(String name) {
		return this.getValueOfSelected(name, 0, new Computer() {
			public double compute(double result, double value) {
				return result + value;
			}
		});
	}

	/**
	 * 被选择行的某列求最大值
	 */
	public String getMaxOfSelected(String name) {
		return this.getValueOfSelected(name, Double.MIN_VALUE, new Computer() {
			public double compute(double result, double value) {
				return Math.max(result, value);
			}
		});
	}

	/**
	 * 被选择行的某列求最小值
	 */
	public String getMinOfSelected(String name) {
		return this.getValueOfSelected(name, Double.MAX_VALUE, new Computer() {
			public double compute(double result, double value) {
				return Math.min(result, value);
			}
		});
	}

	/**
	 * 被选择的行进行某种计算
	 * 
	 * @param name
	 *            列名
	 * @param initValue
	 *            计算结果的初值
	 * @param computer
	 *            计算方法
	 */
	public String getValueOfSelected(String name, double initValue,
			Computer computer) {
		// 如果没有数据，返回0
		if (this.datas == null || this.datas.isEmpty()) {
			return "0";
		}
		double result = initValue;
		Column col = this.getColumByName(name);
		String field = col.field;
		Iterator iter = this.selected.iterator();
		while (iter.hasNext()) {
			String str = (String) iter.next();
			Hashtable data = (Hashtable) this.datas.get(Integer.parseInt(str));
			String string = (String) data.get(field);
			double value = 0;
			try {
				value = Double.parseDouble(string);
			} catch (Exception e) {
				// 忽略数据异常
			}
			result = computer.compute(result, value);
		}
		return result + "";
	}

	/**
	 * 根据当前值以及结果，返回结果
	 */
	private interface Computer {
		public double compute(double result, double value);
	}

	/**
	 * 根据列名得到列
	 * 
	 * @param name
	 * @return
	 */
	private Column getColumByName(String name) {
		Iterator iterator = this.columns.iterator();
		while (iterator.hasNext()) {
			Column column = (Column) iterator.next();
			if (column.field.equals(name)) {
				return column;
			}
		}
		return null;
	}

	/**
	 * 列的说明
	 */
	protected class Column {
		/**
		 * 中文名
		 */
		String name;

		/**
		 * 字段名
		 */
		String field;

		/**
		 * 类型
		 */
		String type;

		/**
		 * 是否小计
		 */
		String addup;

		/**
		 * 描述本列数据的span元素
		 */
		Element element;
	}
}
